# coding: utf-8
import json

from sqlalchemy.sql import text, or_, func

from app.extensions import db
from app.models import BaseModel
from app.products.constant import (
    SceneType, ColorType, Waterproof, Transport,
    SpecUnit, CalculateItem,
    TypeToName, CONSULT_DISPLAY, TagType, ParamValueType,
    VisibleType, DraftStatus)


class ProductType(BaseModel):
    """
    产品类型
    deprecated
    """
    __tablename__ = 'product_types'

    # 产品名称
    name = db.Column(db.String(128), nullable=False, default='')

    @classmethod
    def init_data_for_dev(cls):
        """
        初始化数据，暂时作为测试使用
        :return:
        """
        names = [
            '模组', '原装箱体', '组装-租赁箱体',
            '组装-普通标准箱体', '箱体扣件', '接收卡', '异步接收卡',
            '发送卡', '异步发送卡', '视频处理器', '视频拼接器',
            '异步控制器', '网卡', '型材', '型材拐角', '型材接口',
            '挂件', '方管', '特殊方管', '磁铁', '螺丝', '钢结构',
            '钢结构离地高度加价', '钢结构加焊不锈钢加价', '钢结构换成铝单板加价',
            '电源', '电源线', '排线', '3米网线', '1.5米网线', '电脑', '排气扇',
            '空调', '功放', '音柱', '避雷针', '安防拼接器', '配电柜'
        ]
        for name in names:
            cls.create(name=name)
        db.session.commit()


class TechnologyParams(BaseModel):
    """
    原名：产品规格（现改为技术参数）
    ProductSpec   ---> TechnologyParams
    product_specs ---> technology_params
    """

    __tablename__ = 'technology_params'

    json_keys = {
        'options': list
    }

    # 产品类型id
    product_type_id = db.Column(
        db.Integer(),
        index=True
    )
    # 参数名称
    name = db.Column(db.String(128), nullable=False)
    # 默认值
    default_value = db.Column(db.String(512), default='')
    # 单位
    unit = db.Column(db.Integer())
    # 是否计算项
    calculate_item = db.Column(db.Integer(), default=0)
    # 是否显示(是否为标题)
    is_display = db.Column(db.Boolean(), default=False)
    # 排序权重
    weight = db.Column(db.Integer(), default=0)
    # 是否必填
    is_required = db.Column(
        db.Boolean(), default=False, server_default=text('false')
    )
    # 显示规则
    display_rule = db.Column(
        db.String(128), server_default=text("'{}'"), default='{}'
    )
    # 参数类型(用作输入值的检查) 1整型、2字符串、3列表
    value_type = db.Column(db.Integer(), default=0)
    # 选项值
    options = db.Column(db.JSON())
    # 父id
    parent_id = db.Column(db.Integer(), nullable=True, default=0)
    # 标签类型(输入项、跳转选择、单选、多选)
    tag_type = db.Column(
        db.Integer(),
        nullable=False,
        server_default=text('1')
    )
    # 输入提示
    placeholder = db.Column(
        db.String(64), default='', server_default=text("''")
    )

    @property
    def unit_display(self):
        return SpecUnit().display_mapping.get(self.unit, '')

    @property
    def calculate_item_display(self):
        return CalculateItem.mapping.get(self.calculate_item, '')

    @property
    def is_title_display(self):
        return '是' if self.is_display else '否'

    @property
    def required_display(self):
        return '是' if self.is_required else '否'

    @property
    def product_type_name(self):
        return TypeToName.mapping.get(self.product_type_id, '')

    @property
    def tag_type_display(self):
        return TagType.mapping.get(self.tag_type, '')

    @classmethod
    def specs_choices(cls, product_type_id):
        specs = cls.query.filter(
            cls.product_type_id == product_type_id
        ).with_entities(
            cls.id,
            cls.name
        ).all()
        return specs

    @classmethod
    def params_parents_choices(cls, product_type_id):
        choices = cls.query.filter(
            cls.product_type_id == product_type_id,
            or_(
                cls.parent_id.is_(None),
                cls.parent_id == 0
            )
        ).with_entities(
            cls.id,
            cls.name
        ).all()
        return choices


class ProductTemplate(BaseModel):
    """
    产品（需改成产品模板）
    Product   ---> ProductTemplate
    products ---> product_templates
    """

    filter_dict = {
        'scene': (),
        'color': (),
        'waterproof': (),
        'transport': ()
    }

    json_keys = {
        'pictures': list
    }

    __tablename__ = 'product_templates'

    # 产品类型id
    product_type_id = db.Column(
        db.Integer(),
        index=True
    )
    # 产品名称
    name = db.Column(db.String(128), nullable=False, index=True, default='')
    # 品牌
    brand = db.Column(db.String(64), index=True)
    # 成本价格
    price = db.Column(db.DECIMAL(9, 2), default=0)
    # 建议零售价
    suggest_price = db.Column(db.DECIMAL(9, 2), default=0)
    # 信息来源
    source = db.Column(db.String(256), default='')
    # 权重
    weight = db.Column(db.Integer(), default=0)
    # 场景（户内外）
    scene = db.Column(db.Integer())
    # 颜色
    color = db.Column(db.Integer())
    # 防水
    waterproof = db.Column(db.Integer())
    # 信号传输方式
    transport = db.Column(db.Integer())
    # 距离上限
    distance_upper = db.Column(db.Integer())
    # 距离下限
    distance_lower = db.Column(db.Integer())
    # 总带载点数上限
    pixel_upper = db.Column(db.Integer())
    # 总带载点数下限
    pixel_lower = db.Column(db.Integer())
    # 面积上限
    area_upper = db.Column(db.Integer())
    # 面积下限
    area_lower = db.Column(db.Integer())
    # 产品备注或者说明
    remark = db.Column(db.Text(), default='')
    # 图片
    pictures = db.Column(db.JSON(), default='[]')
    # 品牌id
    brand_id = db.Column(db.Integer())
    # 状态（1上架、0下架）
    status = db.Column(db.Integer())
    # 规格项配置
    spec_settings = db.Column(db.JSON())
    # 型号id
    brand_model_id = db.Column(db.Integer())

    @property
    def scene_display(self):
        return SceneType.mapping.get(self.scene, '')

    @property
    def color_display(self):
        return ColorType.mapping.get(self.color, '')

    @property
    def waterproof_display(self):
        return Waterproof.mapping.get(self.waterproof, '')

    @property
    def transport_display(self):
        return Transport.mapping.get(self.transport, '')

    @property
    def product_type_name(self):
        return TypeToName.mapping.get(self.product_type_id, '')

    @property
    def brand_model_name(self):
        """
        create by ld_wu 2018-01-16
        产品型号名称
        :return:
        """
        if self.brand_model_id:
            model = BrandModel.get_by_id(self.brand_model_id)
            if model:
                return model.model_name
        return ''

    @property
    def title_display(self):
        """
        create by ld_wu 2018-01-17
        产品标题信息
        :return:
        """
        params = ProductToParam.query.filter(
            ProductToParam.product_template_id == self.id,
            ProductToParam.deleted_at == 0,
            ProductToParam.is_display.__eq__(True)
        ).order_by(
            ProductToParam.weight.desc()
        ).all()
        return ''.join([each.value_display for each in params])

    def product_price(self, user=None):
        query = ProductDesc.query.filter(
            ProductDesc.product_template_id == self.id,
            ProductDesc.deleted_at == 0,
            ProductDesc.min_price > 0
        ).order_by(
            ProductDesc.min_price.asc()
        )

        if user:
            # 自身报价
            query = query.filter(
                ProductDesc.supplier_id == user.id
            )

        price = query.first()
        if price:
            if user:
                setattr(self, 'is_self', True)
            return price.min_price
        return self.suggest_price or 0

    @property
    def spec_display(self):
        specs = ProductToParam.query.filter(
            ProductToParam.product_template_id == self.id,
            ProductToParam.is_display.__eq__(True)
        ).order_by(ProductToParam.technology_param_id)
        spec_info = ' '.join(
            ['{}{}'.format(spec.value, spec.unit_display)
             for spec in specs if spec.value
             ]
        )
        return spec_info


class ProductToParam(BaseModel):
    """
    产品具体技术参数
    ProductToSpec   ---> ProductToParams
    product_to_specs ---> product_to_params
    """

    __tablename__ = 'product_to_params'

    json_keys = {
        'options': list
    }

    # 产品id
    product_template_id = db.Column(
        db.Integer(),
        db.ForeignKey('product_templates.id'),
        index=True
    )
    # 产品规格id
    technology_param_id = db.Column(db.Integer())
    # 规格设定的值
    value = db.Column(db.String(512), default='')
    # 冗余规格名称
    name = db.Column(db.String(128))
    # 冗余规格单位
    unit = db.Column(db.Integer())
    # 是否计算项
    calculate_item = db.Column(db.Integer(), default=0)
    # 是否显示
    is_display = db.Column(db.Boolean(), default=False)
    # 排序权重
    weight = db.Column(db.Integer(), default=0, server_default=text('0'))
    # 是否必填
    is_required = db.Column(
        db.Boolean(), default=False, server_default=text('false')
    )
    # 参数类型(用作输入值的检查)
    value_type = db.Column(db.Integer(), default=0)
    # 显示规则
    display_rule = db.Column(
        db.String(128), server_default=text("'{}'"), default='{}'
    )
    # 选项值
    options = db.Column(db.JSON(), default=[])

    # 父id
    parent_id = db.Column(db.Integer(), nullable=True)

    tag_type = db.Column(
        db.Integer(),
        nullable=False,
        server_default=text('1')
    )
    # 输入提示
    placeholder = db.Column(
        db.String(64), default='', server_default=text("''")
    )

    @property
    def unit_display(self):
        return SpecUnit().display_mapping.get(self.unit, '')

    @property
    def value_display(self):
        if self.value_type == ParamValueType.LIST:
            try:
                value = '、'.join(json.loads(self.value))
            except:
                value = self.value
        else:
            value = self.value
        return self.display_rule.format(value) if value else ''


class ProductPrice(BaseModel):
    """
    create by ld_wu 2017-09-27
    工程商自行供货价格记录
    """
    __tablename__ = 'product_prices'

    supplier_id = db.Column(db.Integer(), index=True)
    # 产品说明id
    product_desc_id = db.Column(db.Integer(), nullable=False, index=True)
    product_template_id = db.Column(
        db.Integer(),
        db.ForeignKey('product_templates.id'),
        index=True
    )
    price = db.Column(db.DECIMAL(9, 2), default=0)
    # 规格组合键
    spec_key = db.Column(db.String(128), default='')
    # 规格冗余值的信息
    spec_info = db.Column(db.JSON(), default='')
    # 是否议价
    is_consult = db.Column(
        db.Boolean(),
        default=False,
        server_default=text('false')
    )
    # 规格值
    spec_value = db.Column(db.String(128))

    @classmethod
    def update_price(cls, product_id, supplier_id, price):
        obj = ProductPrice.get_by_args(
            product_template_id=product_id,
            supplier_id=supplier_id
        )
        if obj:
            obj.price = price
            obj.deleted_at = 0
        else:
            ProductPrice.create(
                supplier_id=supplier_id,
                product_template_id=product_id,
                price=price
            )


class ProductDesc(BaseModel):
    """
    create by ld_wu 2017-12-20
    产品说明(采购说明), 作为供应商发布产品的标识，与供应商发布产品数一一对应
    """
    __tablename__ = 'product_desc'

    # 起订数量
    min_quantity = db.Column(db.Integer(), default=0, nullable=False)
    product_type_id = db.Column(
        db.Integer(), default=0, index=True, nullable=False
    )
    # 产品模板id
    product_template_id = db.Column(db.Integer(), index=True)
    # 产品发布人
    supplier_id = db.Column(db.Integer(), index=True)
    # 保修期
    warranty_period = db.Column(db.Integer(), default=0)
    # 交货期
    delivery_period = db.Column(db.Integer(), default=0)
    # 采购说明
    remark = db.Column(db.TEXT(), default='')
    # 最低价
    min_price = db.Column(db.DECIMAL(10, 2), default=0)
    # 最高价
    max_price = db.Column(db.DECIMAL(10, 2), default=0)
    # 是否议价
    is_consult = db.Column(
        db.Boolean(),
        default=False,
        server_default=text('false')
    )
    # 可见类型 1 好友可见 11 自己可见 21 全国可见 31 部分可见
    visible_type = db.Column(db.Integer(), nullable=False)
    # 可见省份id， 逗号隔开
    area_ids = db.Column(db.String(600), default='')

    @property
    def visible_type_display(self):
        return VisibleType.mapping.get(self.visible_type, '')

    @classmethod
    def price_statistics(cls, product_type_id=None):
        """
        报价总览
        :return:
        """
        query = cls.query
        if product_type_id:
            query = query.filter(
                cls.product_type_id == product_type_id
            )
        query = query.filter(
            cls.deleted_at == 0
        ).group_by(
            cls.product_template_id
        ).with_entities(
            func.count(cls.supplier_id.distinct()).label('user_count'),
            func.count(cls.id).label('price_count'),
            cls.product_template_id,
            func.max(cls.max_price).label('max_price'),
            func.min(cls.min_price).label('min_price'),
            func.max(cls.is_consult).label('is_consult')
        )
        return query.all()


class Brand(BaseModel):
    """
    产品品牌
    """
    filter_dict = {
        'product_type_id': ()
    }

    search_keys = ('brand_name', )

    __tablename__ = 'brands'

    product_type_id = db.Column(db.Integer(), nullable=False, index=True)
    # 品牌名称
    brand_name = db.Column(db.String(128), default='')
    # 排名权重
    weight = db.Column(db.Integer(), default=0)
    # 同一产品类下名字唯一
    __table_args__ = (db.UniqueConstraint('brand_name', 'product_type_id'), )

    @property
    def product_type_name(self):
        return TypeToName.mapping.get(self.product_type_id, '')

    @classmethod
    def brand_choices(cls, product_type_id):
        return cls.query.filter(
            cls.product_type_id == product_type_id,
            cls.deleted_at == 0
        ).with_entities(
            cls.id,
            cls.brand_name
        )


class BrandModel(BaseModel):
    """
    产品型号
    """
    search_keys = ('model_name',)

    filter_dict = {
        'product_type_id': (),
        'brand_id': ()
    }
    __tablename__ = 'brand_models'

    product_type_id = db.Column(db.Integer(), nullable=False, index=True)
    brand_id = db.Column(db.Integer(), nullable=False, index=True)
    # 型号名称
    model_name = db.Column(db.String(128), default='')
    # 排名权重
    weight = db.Column(db.Integer(), default=0, server_default=text("'0'"))

    @property
    def product_type_name(self):
        return TypeToName.mapping.get(self.product_type_id, '')

    @property
    def brand_name(self):
        brand = Brand.get_by_id(self.brand_id)
        return brand.brand_name if brand else ''

    @classmethod
    def model_choices(cls, brand_id):
        return cls.query.filter(
            cls.brand_id == brand_id,
            cls.deleted_at == 0
        ).with_entities(
            cls.id,
            cls.model_name
        )


class Order(BaseModel):
    """
    订单信息
    """
    filter_dict = {
        'order_no': ()
    }

    __tablename__ = 'orders'
    # 出售人id
    seller_id = db.Column(db.Integer(), nullable=False, index=True)
    # 购买人id
    buyer_id = db.Column(db.Integer(), nullable=False, index=True)
    # 购买人姓名
    buyer_name = db.Column(db.String(128), default='')
    # 购买人电话
    buyer_mobile = db.Column(db.String(32), default='')
    # 订单编号
    order_no = db.Column(db.String(32), nullable=False, index=True)
    # 订单总价
    total = db.Column(db.DECIMAL(10, 2), default=0)
    # 是否议价
    is_consult = db.Column(
        db.Boolean(),
        default=False,
        server_default=text('false')
    )

    @property
    def total_display(self):
        """
        总价展示
        :return:
        """
        return CONSULT_DISPLAY if self.is_consult else self.total

    @property
    def seller_name(self):
        """
        create by ld_wu 2018-01-02
        出售人名字
        :return:
        """
        from app.op.models import User
        user = User.get_by_id(self.seller_id)
        return user.nickname if user else ''


class OrderRemark(BaseModel):

    """
    订单备注信息
    """

    __tablename__ = 'order_remarks'

    # 备注人
    user_id = db.Column(db.Integer(), nullable=False)
    # 订单id
    order_id = db.Column(
        db.Integer(), db.ForeignKey('orders.id'), index=True, nullable=False
    )
    # 备注信息
    remark = db.Column(db.String(256), default='')


class OrderItem(BaseModel):
    """
    订单商品信息
    """
    __tablename__ = 'order_items'

    # 订单id
    order_id = db.Column(
        db.Integer(), db.ForeignKey('orders.id'), index=True, nullable=False
    )
    # 产品id
    product_desc_id = db.Column(
        db.Integer(),
        db.ForeignKey('product_desc.id'),
        index=True
    )
    # 产品模板id
    product_template_id = db.Column(db.Integer())
    # 规格报价id
    product_prices_id = db.Column(db.Integer())
    # 规格值
    spec_value = db.Column(db.String(128))
    # 产品信息
    product_info = db.Column(db.JSON(), default='')
    # 购买产品的数量
    quantity = db.Column(db.Integer(), default=0)
    # 产品单价
    price = db.Column(db.DECIMAL(10, 2), default=0)
    # 是否议价
    is_consult = db.Column(
        db.Boolean(),
        default=False,
        server_default=text('false')
    )


class ProductDraft(BaseModel):
    """
    create by ld_wu 2017-12-20
    待审核产品（产品草稿）
    """
    filter_dict = {
        'status': ()
    }

    __tablename__ = 'product_drafts'
    # 产品模板id
    product_template_id = db.Column(
        db.Integer(),
        db.ForeignKey('product_templates.id'),
        index=True
    )
    # 审核备注
    remark = db.Column(db.String(256), default='')
    # 审核状态(1审理中、11拒绝、21通过、51审理结束)
    status = db.Column(db.Integer(), default=0, nullable=False)
    # 审核时间
    approval_at = db.Column(db.Integer(), default=0)
    # 产品信息
    product_info = db.Column(db.JSON(), default='')
    # 提交人
    applicant_id = db.Column(db.Integer(), default=0, nullable=False)
    # 审批人
    approver_id = db.Column(db.Integer(), default=0)

    product_template = db.relationship(
        'ProductTemplate',
        backref=db.backref('drafts', lazy='dynamic')
    )

    @property
    def is_for_new(self):
        """
        是否为新增
        :return:
        """
        return False if self.product_template_id else True

    @property
    def status_display(self):
        """
        create by ld_wu 2018-01-02
        审核状态显示
        :return:
        """
        return DraftStatus(self.status).display

    @property
    def product_type_name(self):
        """
        产品草稿产品类名称
        :return:
        """
        return TypeToName.mapping.get(self.product_info.get('product_type_id'))


class SpecTemplate(BaseModel):
    """
    create by ld_wu 2017-12-20
    规格模板
    """
    filter_dict = {
        'product_type_id': ()
    }

    search_keys = ('name',)

    json_keys = {
        'options': list
    }

    __tablename__ = 'spec_templates'

    # 产品类
    product_type_id = db.Column(db.Integer(), nullable=False, index=True)
    # 规格名称
    name = db.Column(db.String(128), default='')
    # 是否输入类型
    is_input_type = db.Column(db.Boolean(), default=False)
    # 权重（用于排序）
    weight = db.Column(db.Integer(), default=0)
    # 选项值
    options = db.Column(db.JSON())
    # 单位
    unit = db.Column(db.Integer())
    # 输入提示
    placeholder = db.Column(
        db.String(64), default='', server_default=text("''")
    )

    @property
    def product_type_name(self):
        return TypeToName.mapping.get(self.product_type_id, '')

    @property
    def unit_display(self):
        return SpecUnit().display_mapping.get(self.unit, '')

    @property
    def input_type_display(self):
        return '是' if self.is_input_type else '否'

    @classmethod
    def spec_choices(cls, product_type_id):
        query = cls.query.filter(
            cls.product_type_id == product_type_id,
            cls.deleted_at == 0
        )

        return [
            dict(
                id=each.id,
                spec_templates_id=each.id,
                unit=each.unit,
                name=each.name,
                is_input_type=each.is_input_type,
                options=each.options,
                unit_display=each.unit_display
            ) for each in query.all()
        ]

    @classmethod
    def spec_mapping(cls, product_type_id):
        templates = cls.query.filter(
            cls.product_type_id == product_type_id,
            cls.deleted_at == 0
        )
        return {
            each.id: dict(
                spec_templates_id=each.id,
                options=each.options,
                name=each.name,
                values=each.options
            )
            for each in templates
        }


class CartItem(BaseModel):
    """
    create by ld_wu 2017-12-28
    购物车
    """
    __tablename__ = 'cart_items'

    # 购买人id
    user_id = db.Column(db.Integer(), nullable=False, index=True)
    # 代购批发商id
    supplier_id = db.Column(db.Integer(), nullable=True)
    # 产品报价说明id
    product_desc_id = db.Column(db.Integer(), nullable=False)
    # 规格报价id
    product_prices_id = db.Column(db.Integer(), nullable=True)
    # 数量
    quantity = db.Column(db.Integer(), default=0, nullable=False)


def make_sure_json_list(options):
    try:
        data = json.loads(options)
        return isinstance(data, list)
    except ValueError as e:
        print(e)
        return False
